home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 37 / Amiga Format CD37 (1999-02-16)(Future Publishing)(GB)(Track 1 of 3)[!][issue 1999-03].iso / -screenplay- / shareware / invasionforce / source / map_display.c < prev    next >
C/C++ Source or Header  |  1999-01-09  |  18KB  |  563 lines

  1. /*
  2.    map_display.c -- Invasion Force map display module
  3.  
  4.    This module has functions for displaying game maps in the various
  5.    program modes: map editor, movement and survey, and production.
  6.  
  7.    Lower level graphic functions go in graphics.c.
  8.  
  9.    This source code is free.  You may make as many copies as you like.
  10.  
  11.  ***********************************************************************
  12.  ***            THE GAME OF INVASION FORCE FOR THE AMIGA             ***
  13.  ***                         by Tony Belding                         ***
  14.  ***********************************************************************
  15.  
  16.  The game was written with the SAS/C compiler.
  17.  Compatibility with other compilers is anybody's guess.
  18. */
  19.  
  20. // standard header for all program modules
  21. #include "global.h"
  22.  
  23. #define ME_MAP 1     // mode indicators for the map
  24. #define GP_MAP 2
  25. #define PM_MAP 3
  26.  
  27. // NOTE: functions beginning with ME_ are for the map editor, GP_ for
  28. // gameplay (i.e. movement and survey modes), and PM_ for production mode.
  29.  
  30. // Following is same as plex_draw_roads(), except it also updates
  31. // the icons of surrounding hexes: necessary to keep roads from
  32. // over-writing cities or other objects
  33.  
  34. void GP_draw_roads(col,row)
  35. int col, row;
  36. {
  37.    int hexes, ctr, flag;
  38.    struct MapIcon *piece;
  39.  
  40.    // outline_hex(col,row,WHITE);
  41.    hexes = adjacent(col,row);
  42.    for (ctr=0; ctr<hexes; ctr++) {
  43.       flag = get_flags(PLAYER.map,hexlist[ctr].col,hexlist[ctr].row);
  44.       if (flag & ROAD) {
  45.          draw_road(col,row,hexlist[ctr].col,hexlist[ctr].row);
  46.  
  47.          // search for icons to redraw
  48.          for (piece=(struct MapIcon *)PLAYER.icons.mlh_Head; piece->inode.mln_Succ; piece=(struct MapIcon *)piece->inode.mln_Succ) {
  49.             if (piece->col==hexlist[ctr].col && piece->row==hexlist[ctr].row) {
  50.                if (piece->type==CITY)
  51.                   plot_city(piece->col,piece->row,roster[piece->owner].color,FALSE);
  52.                else
  53.                   plot_icon(piece->type,piece->col,piece->row,roster[piece->owner].color,piece->token,piece->stacked!=NULL);
  54.                break;
  55.             }
  56.          }
  57.       }
  58.    OD
  59. }
  60.  
  61.  
  62. void ME_draw_roads(col,row)
  63. int col, row;
  64. {
  65.    int hexes, ctr, flag;
  66.    struct City *metro;
  67.  
  68.    // outline_hex(col,row,WHITE);
  69.    hexes = adjacent(col,row);
  70.    for (ctr=0; ctr<hexes; ctr++) {
  71.       flag = get_flags(t_grid,hexlist[ctr].col,hexlist[ctr].row);
  72.       if (flag & ROAD) {
  73.          draw_road(col,row,hexlist[ctr].col,hexlist[ctr].row);
  74.  
  75.          // search for cities to update
  76.          for (metro=(struct City *)city_list.mlh_Head;
  77.          metro->cnode.mln_Succ;
  78.          metro=(struct City *)metro->cnode.mln_Succ) {
  79.             if (metro->col==hexlist[ctr].col && metro->row==hexlist[ctr].row) {
  80.                plot_city(metro->col,metro->row,roster[metro->owner].color,FALSE);
  81.                break;
  82.             FI
  83.          OD
  84.       FI
  85.    OD
  86. }
  87.  
  88.  
  89. // Yet another draw_roads function, this time for the production mode map.
  90. // It will correctly update the cities in the surrounding hexes.
  91.  
  92. void PM_draw_roads(col,row)
  93. int col, row;
  94. {
  95.    int hexes, ctr, flag;
  96.  
  97.    // outline_hex(col,row,WHITE);
  98.    hexes = adjacent(col,row);
  99.    for (ctr=0; ctr<hexes; ctr++) {
  100.       flag = get_flags(PLAYER.map,hexlist[ctr].col,hexlist[ctr].row);
  101.       if (flag & ROAD) {
  102.          struct City *metro=city_hereP(hexlist[ctr].col,hexlist[ctr].row);
  103.  
  104.          draw_road(col,row,hexlist[ctr].col,hexlist[ctr].row);
  105.          if (metro) {
  106.             if (metro->owner==player)
  107.                plot_icon(metro->unit_type,metro->col,metro->row,PLAYER.color,NULL,FALSE);
  108.             else
  109.                if (get(PLAYER.map,metro->col,metro->row)!=HEX_UNEXPLORED) {
  110.                   /*
  111.                      This bit is going to be a little tricky.  I must search
  112.                      the player's map icons to determine who he thinks owns the
  113.                      city (because his info could be out of date).
  114.                   */
  115.                   struct MapIcon *piece = (struct MapIcon *)PLAYER.icons.mlh_Head;
  116.                   int color=WHITE;
  117.  
  118.                   for (;piece->inode.mln_Succ;piece=(struct MapIcon *)piece->inode.mln_Succ)
  119.                      if (piece->col==metro->col && piece->row==metro->row) {
  120.                         color = roster[piece->owner].color;
  121.                         break;
  122.                      FI
  123.                   if (metro->recon[player]==CITY)
  124.                      plot_city(metro->col,metro->row,color,FALSE);
  125.                   else
  126.                      plot_icon(metro->recon[player],metro->col,metro->row,color,0,0);
  127.                FI
  128.          FI
  129.       FI
  130.    OD
  131. }
  132.  
  133.  
  134. // I want to update the display of one hex only
  135.  
  136. void GP_update_hex_display(col,row)
  137. int col, row;
  138. {
  139.    struct MapIcon *piece=(struct MapIcon *)PLAYER.icons.mlh_Head;
  140.  
  141.    if (!VALID_HEX(col,row))
  142.       return;
  143.    if (visibleP(col,row))
  144.       plot_hex(col,row,get(PLAYER.map,col,row));
  145.  
  146.    if (get_flags(PLAYER.map,col,row)&ROAD)
  147.       GP_draw_roads(col,row);
  148.  
  149.    for (; piece->inode.mln_Succ; piece = (struct MapIcon *)piece->inode.mln_Succ) {
  150.       if (piece->col != col || piece->row != row)
  151.          continue;
  152.       if (piece->type==CITY) {
  153.          BOOL defended = FALSE;
  154.          struct Unit *unit =  (struct Unit *)unit_list.mlh_Head;
  155.  
  156.          if (piece->owner==player)
  157.             for (; unit->unode.mln_Succ; unit = (struct Unit *)unit->unode.mln_Succ)
  158.                if (unit->col==piece->col && unit->row==piece->row) {
  159.                   defended = TRUE;
  160.                   break;
  161.                FI
  162.  
  163.          // display city on map
  164.          plot_city(piece->col,piece->row,roster[piece->owner].color,defended);
  165.       } else
  166.          plot_icon(piece->type,piece->col,piece->row,roster[piece->owner].color,piece->token,piece->stacked!=NULL);
  167.    OD
  168. }
  169.  
  170.  
  171. void GP_update_at_hex(col,row)
  172. int col, row;
  173. {
  174.    GP_update_hex_display(col,row);
  175.    GP_update_hex_display(col-1,row);
  176.    GP_update_hex_display(col+1,row);
  177.    GP_update_hex_display(col,row-1);
  178.    GP_update_hex_display(col,row+1);
  179.    if (row%2) {  // i.e. if it's an odd-numbered column
  180.       GP_update_hex_display(col+1,row-1);
  181.       GP_update_hex_display(col+1,row+1);
  182.    } else {
  183.       GP_update_hex_display(col-1,row-1);
  184.       GP_update_hex_display(col-1,row+1);
  185.    FI
  186. }
  187.  
  188.  
  189. void PM_update_hex(col,row)
  190. {
  191.    int terra;
  192.    struct City *metro=(struct City *)city_list.mlh_Head;
  193.  
  194.    terra = get(PLAYER.map,col,row);
  195.    if (terra!=HEX_UNEXPLORED) {
  196.       plot_hex(col,row,terra);
  197.       if (get_flags(PLAYER.map,col,row)&ROAD)
  198.          PM_draw_roads(col,row);
  199.    }
  200.  
  201.    for (;metro->cnode.mln_Succ;metro=(struct City *)metro->cnode.mln_Succ)
  202.       if (metro->col==col && metro->row==row) {
  203.          if (metro->owner==player)
  204.             plot_icon(metro->unit_type,metro->col,metro->row,PLAYER.color,NULL,FALSE);
  205.          else
  206.             if (get(PLAYER.map,metro->col,metro->row)!=HEX_UNEXPLORED) {
  207.                struct MapIcon *piece = (struct MapIcon *)PLAYER.icons.mlh_Head;
  208.                int color=WHITE;
  209.  
  210.                for (;piece->inode.mln_Succ;piece=(struct MapIcon *)piece->inode.mln_Succ)
  211.                   if (piece->col==metro->col && piece->row==metro->row) {
  212.                      color = roster[piece->owner].color;
  213.                      break;
  214.                   FI
  215.                plot_city(metro->col,metro->row,color,FALSE);
  216.             FI
  217.          break;
  218.       FI
  219. }
  220.  
  221. void ME_draw_mapstrip(x0,y0,x1,y1)
  222. int x0, y0, x1, y1;
  223. {
  224.    int xc, yc;
  225.  
  226.    // display the hex terrain
  227.    for (yc=y0; yc<=y1; yc++)
  228.       for (xc=x0; xc<=x1; xc++) {
  229.          int xw=xc, yw=yc;
  230.  
  231.          wrap_coords(&xw,&yw);
  232.          if (visibleP(xw,yw)) {  // basic bounds checking
  233.             int terra;
  234.  
  235.             if (VALID_HEX(xw,yw)) {
  236.                terra = get(t_grid,xw,yw);
  237.                plot_hex(xw,yw,terra);
  238.                if (get_flags(t_grid,xw,yw)&ROAD)
  239.                   ME_draw_roads(xw,yw);
  240.             FI
  241.          FI
  242.       OD
  243.  
  244.  
  245.    // display the cities
  246.    {
  247.       struct City *metro;
  248.  
  249.       for (metro=(struct City *)city_list.mlh_Head;
  250.       metro->cnode.mln_Succ;
  251.       metro=(struct City *)metro->cnode.mln_Succ) {
  252.          if (within_areaP(metro->col,metro->row,x0,y0,x1,y1)) {
  253.             // display city on map
  254.             plot_city(metro->col,metro->row,roster[metro->owner].color,FALSE);
  255.          FI
  256.       OD
  257.    }
  258. }
  259.  
  260.  
  261. void ME_draw_map()
  262. {
  263.    // clear window
  264.    SetRast(rast_port,LT_GRAY);
  265.  
  266.    // call to this function does all the grunt work,
  267.    // treats display like one huge strip to update
  268.    ME_draw_mapstrip(xoffs-1,yoffs-1,xoffs+disp_wd,yoffs+disp_ht);
  269.  
  270.    update_scrollers();
  271. }
  272.  
  273.  
  274. void ME_smart_scroll(oldxoffs,oldyoffs)
  275. int oldxoffs,oldyoffs;
  276. {
  277.    smart_scroll(oldxoffs,oldyoffs,ME_MAP);
  278. }
  279.  
  280.  
  281. void GP_draw_mapstrip(x0,y0,x1,y1)
  282. int x0,y0,x1,y1;
  283. {  // build the player's map display
  284.    int xc, yc;
  285.  
  286.    // display the hex terrain
  287.    for (yc=y0; yc<=y1; yc++)
  288.       for (xc=x0; xc<=x1; xc++) {
  289.          int xw=xc, yw=yc;
  290.  
  291.          wrap_coords(&xw,&yw);
  292.          if (visibleP(xw,yw)) {  // basic bounds checking
  293.             int terra;
  294.  
  295.             if (VALID_HEX(xw,yw)) {
  296.                terra = get(PLAYER.map,xw,yw);
  297.                if (terra!=HEX_UNEXPLORED) {
  298.                   plot_hex(xw,yw,terra);
  299.                   if (get_flags(PLAYER.map,xw,yw)&ROAD)
  300.                      GP_draw_roads(xw,yw);
  301.                FI
  302.             FI
  303.          FI
  304.       OD
  305.  
  306.  
  307.    // display the icons
  308.    {
  309.       struct MapIcon *piece = (struct MapIcon *)PLAYER.icons.mlh_Head;
  310.       for (; piece->inode.mln_Succ; piece = (struct MapIcon *)piece->inode.mln_Succ) {
  311.          if (within_areaP(piece->col,piece->row,x0,y0,x1,y1)) {
  312.             if (piece->type==CITY) {
  313.                BOOL defended = FALSE;
  314.                struct Unit *unit =  (struct Unit *)unit_list.mlh_Head;
  315.  
  316.                if (piece->owner==player)
  317.                   for (; unit->unode.mln_Succ; unit = (struct Unit *)unit->unode.mln_Succ)
  318.                      if (unit->col==piece->col && unit->row==piece->row) {
  319.                         defended = TRUE;
  320.                         break;
  321.                      FI
  322.  
  323.                // display city on map
  324.                plot_city(piece->col,piece->row,roster[piece->owner].color,defended);
  325.             } else {
  326.                // display unit icon
  327.                plot_icon(piece->type,piece->col,piece->row,roster[piece->owner].color,piece->token,piece->stacked!=NULL);
  328.             FI
  329.          FI
  330.       OD
  331.    }
  332. }
  333.  
  334.  
  335. void GP_draw_map()
  336. {  // build the player's map display
  337.    // clear window
  338.    SetRast(rast_port,LT_GRAY);
  339.  
  340.    // call to this function does all the grunt work,
  341.    // treats display like one huge strip to update
  342.    GP_draw_mapstrip(xoffs-1,yoffs-1,xoffs+disp_wd,yoffs+disp_ht);
  343.  
  344.    update_scrollers();
  345.    display = TRUE;
  346. }
  347.  
  348.  
  349. void smart_scroll(oldxoffs,oldyoffs,mode)
  350. int oldxoffs,oldyoffs,mode;
  351. { // optimized scroll the map for various game modes
  352.    int dx = (xoffs-oldxoffs)*30;  // see how much movement is called for
  353.    int dy = (yoffs-oldyoffs)*24;
  354.    struct Rectangle *rect = &(map_region->bounds);
  355.    int cwidth = rect->MaxX-rect->MinX;
  356.    int cheight = rect->MaxY-rect->MinY;
  357.  
  358.    if (dx==0 && dy==0)
  359.       return;
  360.  
  361.    if (dx>=cwidth || dy>=cheight) {  // too much, might as well redraw
  362.       switch (mode) {
  363.          case GP_MAP:
  364.             GP_draw_map();
  365.             break;
  366.          case ME_MAP:
  367.             ME_draw_map();
  368.             break;
  369.          case PM_MAP:
  370.             PM_draw_map();
  371.       }
  372.       return;
  373.    FI
  374.  
  375.    ScrollRaster(rast_port,dx,dy,rect->MinX,rect->MinY,rect->MaxX,rect->MaxY);
  376.  
  377.    // now the hard part: draw in all the newly visible areas
  378.    // it's similar to view_map() except working on strips,
  379.    // not the whole display at once
  380.  
  381.    // If you have difficulty understanding the following code, you might
  382.    // be comforted to learn that I had difficulty writing it.
  383.    {
  384.       struct Rectangle full, dam;
  385.       int xsiz, ysiz;            // x and y size of damage area in hexes
  386.       int xorg, yorg;            // x and y origin of damage area in hexes
  387.  
  388.       // calculate the clipping area
  389.       dam.MinX = full.MinX = map_window->BorderLeft+2+10;  // 10 to make room for bar
  390.       dam.MinY = full.MinY = map_window->BorderTop+1;
  391.       dam.MaxX = full.MaxX = map_window->Width-map_window->BorderRight-19;
  392.       dam.MaxY = full.MaxY = map_window->Height-map_window->BorderBottom-14;
  393.  
  394.       // calculate the damage area
  395.       if (dx>0) {    // scrolling right
  396.          dam.MinX = full.MaxX-dx;
  397.          if (dam.MinX<full.MinX)
  398.             dam.MinX = full.MinX;
  399.       FI
  400.       if (dx<0) {    // scrolling left
  401.          dam.MaxX = full.MinX-dx;
  402.          if (dam.MaxX>full.MaxX)
  403.             dam.MaxX = full.MaxX;
  404.       FI
  405.       if (dy>0) {    // scrolling down
  406.          dam.MinY = full.MaxY-dy;
  407.          if (dam.MinY<full.MinY)
  408.             dam.MinY = full.MinY;
  409.       FI
  410.       if (dy<0) {    // scrolling up
  411.          dam.MaxY = full.MinY-dy;
  412.          if (dam.MaxY>full.MaxY)
  413.             dam.MaxY = full.MaxY;
  414.       FI
  415.  
  416.       // Having calculated the damaged area in pixel terms, now I must convert that
  417.       // value to hexes.  In other words, I must examine the damaged area and
  418.       // determine the extent of hexes that need to be redrawn.
  419.       xorg = xoffs+(dam.MinX-65)/30;
  420.       yorg = yoffs+(dam.MinY-64)/24;
  421.       xsiz = xoffs+((dam.MaxX-20)/30)-xorg+1;
  422.       ysiz = yoffs+((dam.MaxY-32)/24)-yorg+1;
  423.  
  424.       switch (mode) {
  425.          case GP_MAP:
  426.             GP_draw_mapstrip(xorg,yorg,xorg+xsiz,yorg+ysiz);
  427.             break;
  428.          case ME_MAP:
  429.             ME_draw_mapstrip(xorg,yorg,xorg+xsiz,yorg+ysiz);
  430.             break;
  431.          case PM_MAP:
  432.             PM_draw_mapstrip(xorg,yorg,xorg+xsiz,yorg+ysiz);
  433.       }
  434.  
  435.       // If it's a diagonal scroll, then we probably have two more
  436.       // damage areas to worry about.
  437.       if (xoffs-oldxoffs && yoffs-oldyoffs) {
  438.          int xnwd = disp_wd+2-xsiz;
  439.          int xnorg = (xorg-xoffs<0 ? xorg+xsiz : xorg-xnwd);
  440.          int ynwd = disp_ht+2-ysiz;
  441.          int ynorg = (yorg-yoffs<0 ? yorg+ysiz : yorg-ynwd);
  442.  
  443.          switch (mode) {
  444.             case GP_MAP:
  445.                GP_draw_mapstrip(xnorg,yorg,xnorg+xnwd,yorg+ysiz);
  446.                GP_draw_mapstrip(xorg,ynorg,xorg+xsiz,ynorg+ynwd);
  447.                break;
  448.             case ME_MAP:
  449.                ME_draw_mapstrip(xnorg,yorg,xnorg+xnwd,yorg+ysiz);
  450.                ME_draw_mapstrip(xorg,ynorg,xorg+xsiz,ynorg+ynwd);
  451.                break;
  452.             case PM_MAP:
  453.                PM_draw_mapstrip(xnorg,yorg,xnorg+xnwd,yorg+ysiz);
  454.                PM_draw_mapstrip(xorg,ynorg,xorg+xsiz,ynorg+ynwd);
  455.          }
  456.       FI
  457.    }
  458. }
  459.  
  460.  
  461. void GP_smart_scroll(oldxoffs,oldyoffs)
  462. int oldxoffs,oldyoffs;
  463. {
  464.    smart_scroll(oldxoffs,oldyoffs,GP_MAP);
  465. }
  466.  
  467.  
  468. /*
  469.    All of the PM_ prefix functions are map drawing functions for the
  470.    Production Mode (or Production Map, if you wish) -- the map that shows
  471.    no units, but displays the production type of each city.
  472.  
  473.    PM_draw_mapstrip() draws an area of the production map
  474. */
  475. void PM_draw_mapstrip(x0,y0,x1,y1)
  476. int x0,y0,x1,y1;
  477. {  // build the player's map display
  478.    int xc, yc;
  479.  
  480.    // display the hex terrain
  481.    for (yc=y0; yc<=y1; yc++)
  482.       for (xc=x0; xc<=x1; xc++) {
  483.          int xw=xc, yw=yc;
  484.  
  485.          wrap_coords(&xw,&yw);
  486.          if (visibleP(xw,yw))   // basic bounds checking
  487.          {
  488.             int terra;
  489.  
  490.             if (VALID_HEX(xw,yw)) {
  491.                terra = get(PLAYER.map,xw,yw);
  492.                if (terra!=HEX_UNEXPLORED) {
  493.                   plot_hex(xw,yw,terra);
  494.                   if (get_flags(PLAYER.map,xw,yw)&ROAD)
  495.                      PM_draw_roads(xw,yw);
  496.                FI
  497.             FI
  498.          }
  499.       OD
  500.  
  501.    // display the cities
  502.    {
  503.       struct City *metro=(struct City *)city_list.mlh_Head;
  504.  
  505.       /*
  506.          Show cities owned by the player as unit icons representing the unit
  507.          type the city is producing.  Cities not owned by the player are also
  508.          shown in their correct colors, and it even shows the last known
  509.          production of enemy cities that have been reconned by the player's
  510.          aircraft.
  511.       */
  512.       for (;metro->cnode.mln_Succ;metro=(struct City *)metro->cnode.mln_Succ)
  513.          if (within_areaP(metro->col,metro->row,x0,y0,x1,y1)) {
  514.             if (metro->owner==player)
  515.                plot_icon(metro->unit_type,metro->col,metro->row,PLAYER.color,NULL,FALSE);
  516.             else
  517.                if (get(PLAYER.map,metro->col,metro->row)!=HEX_UNEXPLORED) {
  518.                   /*
  519.                      This bit is going to be a little tricky.  I must search
  520.                      the player's map icons to determine who he thinks owns the
  521.                      city (because his info could be out of date).
  522.                   */
  523.                   struct MapIcon *piece = (struct MapIcon *)PLAYER.icons.mlh_Head;
  524.                   int color=WHITE;
  525.  
  526.                   for (;piece->inode.mln_Succ;piece=(struct MapIcon *)piece->inode.mln_Succ)
  527.                      if (piece->col==metro->col && piece->row==metro->row) {
  528.                         color = roster[piece->owner].color;
  529.                         break;
  530.                      FI
  531.                   if (metro->recon[player]==CITY)
  532.                      plot_city(metro->col,metro->row,color,FALSE);
  533.                   else
  534.                      plot_icon(metro->recon[player],metro->col,metro->row,color,0,0);
  535.                FI
  536.          FI
  537.    }
  538. }
  539.  
  540.  
  541. void PM_draw_map()
  542. {  // build the player's Production Map display
  543.    // clear window
  544.    SetRast(rast_port,LT_GRAY);
  545.  
  546.    // call to this function does all the grunt work,
  547.    // treats display like one huge strip to update
  548.    PM_draw_mapstrip(xoffs-1,yoffs-1,xoffs+disp_wd,yoffs+disp_ht);
  549.  
  550.    update_scrollers();
  551.    display = TRUE;
  552. }
  553.  
  554.  
  555. void PM_smart_scroll(oldxoffs,oldyoffs)
  556. int oldxoffs,oldyoffs;
  557. {
  558.    smart_scroll(oldxoffs,oldyoffs,PM_MAP);
  559. }
  560.  
  561.  
  562. // end of listing
  563.